﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Data;
using System.Diagnostics;

using MyLibrary.TaskScheduler;
using MyLibrary.Data.SqlServer;

namespace MyLibrary.TaskPlan.Service
{
    public enum MonitorStatus
    {
        NotStart,
        Stop,
        Running,
        Pause
    }

    /// <summary>
    /// 计划任务监视器
    /// </summary>
    public class TaskScheduleMonitor
    {
        private string dbConnstring = "user id=DSA_REPORT;password=dsa_report;server=192.168.30.141,2005;database=TaskTest;Connect Timeout=1200;";
        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        public string DBConnstring
        {
            get { return dbConnstring; }
            set { dbConnstring = value; }
        }

        private Timer timer = null;
        private static ScheduledTasks _schedule = new ScheduledTasks();
        string[] _taskName;
        private MonitorStatus _status = MonitorStatus.NotStart;
        private static object _objsync = new object();

        public MonitorStatus MonitorStatus
        {
            get { return _status; }
        }

        public TaskScheduleMonitor()
        {

        }

        /// <summary>
        /// 监视器回调函数
        /// </summary>
        /// <param name="obj"></param>
        private void MonitorTimerCallback(object obj)
        {
            lock (_objsync)
            {
                _taskName = _schedule.GetTaskNames();
                int ret = GetTaskScheduleFromDatabase();
                if (ret == -1) return;
                SyncDatabaseTaskSchedule();
            }
        }

        #region 计划任务操作函数
        /// <summary>
        /// 将设置的Trigger转换成Trigger列表格式
        /// </summary>
        /// <param name="taskName"></param>
        /// <returns></returns>
        private List<Trigger> GetTriggerList(string taskName)
        {
            List<Trigger> lstTrigger = new List<Trigger>();
            return lstTrigger;
        }

        /// <summary>
        /// 建立计划任务
        /// </summary>
        /// <param name="row">数据库中建立计划任务的行</param>
        private void CreateTask(DataRow row)
        {
            string taskName = row["TaskName"].ToString();
            foreach (string name in _taskName)
            {
                if (name == taskName)
                {
                    ModifyTaskStatus(name, "Exists");
                    return;
                }
            }
            //开始创建
            if (String.IsNullOrEmpty(row["Triggers"].ToString()))
            {
                ModifyTaskStatus(taskName, "Error");
                return;
            }

            Task t;
            try
            {
                t = _schedule.CreateTask(taskName);
            }
            catch
            {
                ModifyTaskStatus(taskName, "Exists");
                return;
            }
            SetTaskProperty(row, t, false);
        }

        /// <summary>
        /// 运行计划任务
        /// </summary>
        /// <param name="taskName">计划任务名称</param>
        private void RunTask(string taskName)
        {
            Task t = _schedule.OpenTask(taskName);
            if (t != null)
            {
                if (t.Status != TaskStatus.Running)
                {
                    t.Run();
                    t.Close();
                    ModifyTaskStatus(taskName, "Running");
                }
            }
        }

        /// <summary>
        /// 停止正在运行的任务
        /// </summary>
        /// <param name="taskName">任务名称</param>
        private void StopTask(string taskName)
        {
            Task t = _schedule.OpenTask(taskName);
            if (t != null)
            {
                if (t.Status == TaskStatus.Running)
                {
                    t.Terminate();
                    t.Close();
                    ModifyTaskStatus(taskName, "Stop");
                }
            }
        }

        /// <summary>
        /// 删除计划任务
        /// </summary>
        /// <param name="taskName">计划任务名称</param>
        private void DeleteTask(string taskName)
        {
            _schedule.DeleteTask(taskName);
            ModifyTaskStatus(taskName, "Deleted");
        }

        /// <summary>
        /// 修改计划任务
        /// </summary>
        /// <param name="row">数据库中修改计划任务的行</param>
        private void ModifyTask(DataRow row)
        {
            string taskName = row["TaskName"].ToString();
            Task t = _schedule.OpenTask(taskName);
            if (t != null)
                SetTaskProperty(row, t, true);
            else
                ModifyTaskStatus(taskName, "Error[Modify]");
        }

        /// <summary>
        /// 启用任务
        /// </summary>
        /// <param name="taskName">计划任务名称</param>
        private void EnableTask(string taskName)
        {
            Task t = _schedule.OpenTask(taskName);
            if (t != null)
            {
                if ((t.Flags | TaskFlags.Disabled) == t.Flags)
                    t.Flags = t.Flags ^ TaskFlags.Disabled;
            }
        }

        /// <summary>
        /// 禁用任务
        /// </summary>
        /// <param name="taskName">任务名称</param>
        private void DisableTask(string taskName)
        {
            Task t = _schedule.OpenTask(taskName);
            if (t != null)
            {
                if ((t.Flags | TaskFlags.Disabled) != t.Flags)
                    t.Flags = t.Flags | TaskFlags.Disabled;
            }
        }

        /// <summary>
        /// 设置计划任务的属性,并保存
        /// </summary>
        /// <param name="row">数据库中设置计划任务的行</param>
        /// <param name="t">计划任务</param>
        private void SetTaskProperty(DataRow row, Task t, bool modify)
        {
            string taskName = row["TaskName"].ToString();
            //开始设置
            if (String.IsNullOrEmpty(row["Triggers"].ToString()))
            {
                ModifyTaskStatus(taskName, "Error[EmptyTriggers]");
                return;
            }
            t.ApplicationName = row["ApplicationName"].ToString();
            t.Parameters = row["Parameters"].ToString();
            t.Comment = row["Comment"].ToString();
            t.Creator = row["Creator"].ToString();
            t.WorkingDirectory = row["WorkingDirectory"].ToString();
            string accountName = row["RunningAccount"].ToString();
            if (String.IsNullOrEmpty(accountName))
                t.SetAccountInformation(accountName, (string)null);
            else
                t.SetAccountInformation(accountName, row["RunningAccountPassword"].ToString());
            t.MaxRunTime = new TimeSpan(72, 0, 0);
            t.Priority = ProcessPriorityClass.Normal;
            //解析触发器
            TaskTriggerParse triggers = TaskTriggerParse.LoadTriggers(row["Triggers"].ToString());
            if (modify)
                t.Triggers.Clear();
            //设置触发器
            string[] runTime;
            foreach (TaskTrigger trigger in triggers.TriggerList)
            {
                runTime = trigger.TriggerRunTime.Split(':');
                if (runTime.Length != 2)
                    continue;
                if (trigger.TriggerType == "day")
                    t.Triggers.Add(new DailyTrigger(Convert.ToInt16(runTime[0]),
                        Convert.ToInt16(runTime[1]), Convert.ToInt16(trigger.Period)));
                else if (trigger.TriggerType == "week")
                {
                    DaysOfTheWeek week = DaysOfTheWeek.Monday;
                    if (!String.IsNullOrEmpty(trigger.Number))
                    {
                        string[] weekNumber = trigger.Number.Split(',');
                        foreach (string w in weekNumber)
                        {
                            if (w == "1")
                                week = week | DaysOfTheWeek.Monday;
                            else if (w == "2")
                                week = week | DaysOfTheWeek.Tuesday;
                            else if (w == "3")
                                week = week | DaysOfTheWeek.Wednesday;
                            else if (w == "4")
                                week = week | DaysOfTheWeek.Thursday;
                            else if (w == "5")
                                week = week | DaysOfTheWeek.Friday;
                            else if (w == "6")
                                week = week | DaysOfTheWeek.Saturday;
                            else if (w == "7")
                                week = week | DaysOfTheWeek.Sunday;
                        }
                    }
                    t.Triggers.Add(new WeeklyTrigger(Convert.ToInt16(runTime[0]),
                        Convert.ToInt16(runTime[1]), week, Convert.ToInt16(trigger.Period)));
                }
                else if (trigger.TriggerType == "month")
                {
                    string[] runDays = trigger.Period.Split(',');
                    int[] days = new int[runDays.Length];
                    for (int i = 0; i < runDays.Length; i++)
                        days[i] = Convert.ToInt32(runDays[i]);
                    //如果有指定执行的月份
                    if (!String.IsNullOrEmpty(trigger.Number))
                    {
                        MonthsOfTheYear month = MonthsOfTheYear.January;
                        string[] monthNumber = trigger.Number.Split(',');
                        foreach (string w in monthNumber)
                        {
                            if (w == "1")
                                month = month | MonthsOfTheYear.January;
                            else if (w == "2")
                                month = month | MonthsOfTheYear.February;
                            else if (w == "3")
                                month = month | MonthsOfTheYear.March;
                            else if (w == "4")
                                month = month | MonthsOfTheYear.April;
                            else if (w == "5")
                                month = month | MonthsOfTheYear.May;
                            else if (w == "6")
                                month = month | MonthsOfTheYear.June;
                            else if (w == "7")
                                month = month | MonthsOfTheYear.July;
                            else if (w == "8")
                                month = month | MonthsOfTheYear.August;
                            else if (w == "9")
                                month = month | MonthsOfTheYear.September;
                            else if (w == "10")
                                month = month | MonthsOfTheYear.October;
                            else if (w == "11")
                                month = month | MonthsOfTheYear.November;
                            else if (w == "12")
                                month = month | MonthsOfTheYear.December;
                        }
                        t.Triggers.Add(new MonthlyTrigger(Convert.ToInt16(runTime[0]),
                            Convert.ToInt16(runTime[1]), days, month));
                    }
                    //如果没有
                    else
                        t.Triggers.Add(new MonthlyTrigger(Convert.ToInt16(runTime[0]),
                            Convert.ToInt16(runTime[1]), days));
                }
                else if (trigger.TriggerType == "once")
                    t.Triggers.Add(new RunOnceTrigger(Convert.ToDateTime(trigger.Period + " " + trigger.TriggerRunTime)));
            }

            if (modify)
                t.Save();
            else
                t.Save(taskName);
            t.Close();
        }

        #endregion

        #region 服务操作函数

        /// <summary>
        /// 开始服务
        /// </summary>
        public void Start()
        {
            if (_status == MonitorStatus.NotStart || _status == MonitorStatus.Stop)
            {
                timer = new Timer(MonitorTimerCallback);
                timer.Change(new TimeSpan(0), new TimeSpan(0, 0, 10));
                _status = MonitorStatus.Running;
            }
            else if (_status == MonitorStatus.Pause)
            {
                timer.Change(new TimeSpan(0), new TimeSpan(0, 0, 10));
                _status = MonitorStatus.Running;
            }
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            if (_status == MonitorStatus.Running)
            {
                timer.Change(-1, 0);
                timer.Dispose();
                timer = null;
                _status = MonitorStatus.Stop;
            }
        }

        /// <summary>
        /// 暂停服务
        /// </summary>
        public void Pause()
        {
            if (_status == MonitorStatus.Running)
            {
                timer.Change(-1, 0);
                _status = MonitorStatus.Pause;
            }
        }

        #endregion

        #region 数据库操作函数
        /// <summary>
        /// 从数据库中获取需要进行变动的计划任务
        /// </summary>
        private int GetTaskScheduleFromDatabase()
        {
            //获得数据库配置的计划任务[需要进行修改的任务]
            DataTable table = null;
            try
            {
                table = SQLServerHelper.ExecuteDataset(dbConnstring, CommandType.Text,
                     "Select * From dbo.TaskLogger Where [Status] In ('Add','Modify','Delete','Stop','Run','Disable','Enable')").Tables[0];
            }
            catch(Exception ex)
            {
                EventLog.WriteEntry("TaskMonitor", ex.Message);
                return -1;
            }

            foreach (DataRow row in table.Rows)
            {
                switch (row["Status"].ToString())
                {
                    case "Add":
                        CreateTask(row);
                        break;
                    case "Modify":
                        ModifyTask(row);
                        break;
                    case "Delete":
                        DeleteTask(row["TaskName"].ToString());
                        break;
                    case "Stop":
                        StopTask(row["TaskName"].ToString());
                        break;
                    case "Run":
                        RunTask(row["TaskName"].ToString());
                        break;
                    case "Disable":
                        DisableTask(row["TaskName"].ToString());
                        break;
                    case "Enable":
                        EnableTask(row["TaskName"].ToString());
                        break;
                }
                ModifyTaskStatus(row["TaskName"].ToString(), "Success");
            }
            return 0;
        }

        private void GetTaskMonitorInDatabase()
        {
            DataTable table = SQLServerHelper.ExecuteDataset(this.dbConnstring, CommandType.Text, "Select * From TaskMonitor").Tables[0];

        }

        /// <summary>
        /// 更新指定计划任务的状态
        /// </summary>
        /// <param name="taskName">任务名</param>
        /// <param name="status">状态</param>
        private void ModifyTaskStatus(string taskName, string status)
        {
            string sqlString = "Update dbo.TaskLogger Set [Status]='{0}',UpdateTime=GetDate() Where TaskName='{1}'";
            SQLServerHelper.ExecuteNonQuery(this.dbConnstring, CommandType.Text, String.Format(sqlString, status, taskName));
        }

        /// <summary>
        /// 同步数据库中计划任务的状态
        /// </summary>
        private void SyncDatabaseTaskSchedule()
        {
            string sqlString = "If (Select Count(1) From TaskMonitor Where TaskName='{5}') > 0" +
                " Update TaskMonitor Set NextRunTime='{0}',LastRunTime='{1}',Status='{2}',LastResult='{3}',Creator='{4}' Where TaskName='{5}'" +
                " Else Insert Into TaskMonitor Select '{5}','{0}','{1}','{2}','{3}','{4}'";
            string existsTask = String.Empty;
            int exitCode = -1;

            foreach (string taskName in _taskName)
            {
                Task t = _schedule.OpenTask(taskName);
                try
                {
                    exitCode = t.ExitCode;
                }
                catch
                {
                    exitCode = -1;
                }
                if (t != null)
                {
                    SQLServerHelper.ExecuteNonQuery(this.dbConnstring, CommandType.Text,
                        String.Format(sqlString,
                        t.NextRunTime == DateTime.MinValue ? "1970-01-01" : t.NextRunTime.ToString("yyyy-MM-dd hh:mm:ss"),
                        t.MostRecentRunTime == DateTime.MinValue ? "1970-01-01" : t.MostRecentRunTime.ToString("yyyy-MM-dd hh:mm:ss"),
                        t.Status.ToString(),
                        exitCode,
                        t.Creator,
                        t.Name));
                    existsTask += "'" + t.Name + "',";
                }
            }
            if (existsTask != String.Empty)
            {
                existsTask = existsTask.TrimEnd(',');
                //删除掉已经删除的计划任务
                SQLServerHelper.ExecuteNonQuery(this.dbConnstring, CommandType.Text,
                    "Delete TaskMonitor Where TaskName Not In(" + existsTask + ")" +
                    " Update dbo.TaskLogger Set Status='Deleted',UpdateTime=GetDate() Where TaskName Not In (" + existsTask + ")");
            }
        }
        #endregion
    }
}
